package com.evolve.autotest.compiler;

import java.io.IOException;
import java.io.InputStream;

import org.apache.log4j.Logger;

public class Cursor {

	private final static Logger logger = Logger.getLogger(Cursor.class.getName());

	private final InputStream stream;
	private char currentChar;
	private boolean hasNext;

	public Cursor(InputStream stream) {
		this.stream = stream;
		this.hasNext = true;
	}

	/**
	 * Check if the cursor can go any further on the stream.
	 * 
	 * @return True if stream contains more tokens
	 */
	public boolean hasNextToken() {
		return hasNext;
	}

	/**
	 * Finds the next token. Will keep looking for the entire token and will
	 * stop once it finds on of the characters in any of the two passed arrays
	 * 
	 * @param statementChars
	 *            These characters are ok characters and will end a token
	 * @param closingChars
	 *            These are characters that will end a statement and thus
	 *            indicate that no token was found
	 * @return
	 * @throws TokenNotFoundException
	 */
	public String getNextToken(char[] statementChars, char[] closingChars) throws TokenNotFoundException {

		StringBuffer buffer = new StringBuffer();

		int charNumber = 1;
		try {
			
			charNumber = findNextValidChar();
			
			do {
				currentChar = (char) charNumber;
				logger.info("CHAR: " + currentChar);

				// Check if the read char is in the collection of OK tokens
				if (containsChar(currentChar, statementChars)) {
					// does not include the statement character
					return buffer.toString();
				} else if (containsChar(currentChar, closingChars)) {
					// The token closes a statement and the right token was not
					// found
					throw new TokenNotFoundException("Could not find ending character for token among " + statementChars.toString());
				}

				// Keep appending the characters to form a token
				buffer.append(currentChar);
			} while ((charNumber = stream.read()) != -1);

			// We have no more chars to read
			hasNext = false;
		} catch (IOException e) {
			logger.error("Unable to read from input stream");
			e.printStackTrace();
		}

		return buffer.toString();
	}

	// Read until we have a valid char to start on
	private int findNextValidChar() throws IOException, TokenNotFoundException {
		int charNumber;
		char c = ' ';
		char[] tokens = new char[] { '\r', '\n', '\t', ' ' };
		while ((charNumber = stream.read()) != -1) {
			c = (char)charNumber;
			
			if (!containsChar(c, tokens)) {
				logger.info("Normal ID: " + (int)c);
				return (int)c;
			} else {
				logger.info("Closing token id: " + (int)c );
			}
		}
		
		throw new TokenNotFoundException("Could not find token");
	}

	/**
	 * Checks if a char is in the array
	 * @param readChar
	 * @param tokens
	 * @return
	 */
	private boolean containsChar(char readChar, char[] tokens) {
		for (char endingToken : tokens) {
			if (readChar == endingToken) {
				return true;
			}
		}

		return false;
	}

	public char getLastCharacter() {
		return currentChar;
	}
}
